package com.lcz.manage.util.executor;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.lcz.manage.util.MD5Utils;
import com.lcz.manage.util.exception.CCException;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;

/**
 * @version V3.0
 * @since 2021/5/12
 */
public class GroovyEngineExecutor {

    /***
     * groovy执行方法名
     */
    public static final String STRATEGY_METHOD = "run";

    private static final Object executorLock = new Object();

    private static final Logger log = LoggerFactory.getLogger(GroovyEngineExecutor.class);

    private static Map<String, GroovyObject> groovyObjectMap = new ConcurrentHashMap<>();


    public static Object execute(String groovyScript, Map<String, Object> data) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("GroovyEngineExecutor--开始执行");
        }
        if (StringUtils.isEmpty(groovyScript)) {
            throw new CCException("执行失败：没有可执行的方法！");
        }
        GroovyObject groovyObject = createGroovyObject(groovyScript);
        // 反射调用方法得到返回值
        Object methodResult = groovyObject.invokeMethod(STRATEGY_METHOD, new Object[]{data});
        if (log.isDebugEnabled()) {
            log.debug("GroovyEngineExecutor--执行完成");
        }
        return methodResult;
    }

    /**
     * 创建groovy执行对象
     *
     * @param groovyScript
     * @return
     * @throws Exception
     */
    private static GroovyObject createGroovyObject(String groovyScript) throws Exception {
        String groovyScriptMd5 = MD5Utils.getMd5Code(groovyScript);

        if (!groovyObjectMap.containsKey(groovyScriptMd5)) {
            synchronized (executorLock) {
                if (!groovyObjectMap.containsKey(groovyScriptMd5)) {
                    CompilerConfiguration config = new CompilerConfiguration();
                    config.setSourceEncoding("UTF-8");
                    // 设置该GroovyClassLoader的父ClassLoader为当前线程的加载器(默认)
                    GroovyClassLoader groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);
                    // 获得Script加载后的class
                    Class<?> groovyClass = groovyClassLoader.parseClass(groovyScript);
                    // 获得Script的class的实例
                    GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
                    groovyObjectMap.put(groovyScriptMd5, groovyObject);
                }
            }
        }
        return groovyObjectMap.get(groovyScriptMd5);
    }
}
